/**
 * 
 */
package hyl.base.net.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Vector;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;

import hyl.core.Amy;

/**
 * @author 邹达有
 * @mail 37798955@qq.com
 * 
 * 2022年7月28日
 * 
 */
public class SFtp implements IFtp{

	// private transient Logger log = LoggerFactory.getLogger(this.getClass());

	public ChannelSftp client;

	private Session session;
	/** SFTP 登录用户名 */
	private String username;
	/** SFTP 登录密码 */
	private String password;
	/** 私钥 */
	private String privateKey;
	/** SFTP 服务器地址IP地址 */
	private String host;
	/** SFTP 端口 */
	private int port;

	public SFtp() {
	}

	/**
	 * 构造基于密码认证的sftp对象
	 */
	public SFtp(String username, String password, String host, int port) {
		this.username = username;
		this.password = password;
		this.host = host;
		this.port = port;
	}

	/**
	 * 构造基于秘钥认证的sftp对象
	 */
	public SFtp(String username, String host, int port, String privateKey) {
		this.username = username;
		this.privateKey = privateKey;
		this.host = host;
		this.port = port;
	}

	/**
	 * 连接sftp服务器
	 */
	public void do登录() {
		try {
			JSch jsch = new JSch();
			if (privateKey != null) {
				jsch.addIdentity(privateKey);// 设置私钥
				Amy.Log.info("sftp 连接的 私钥文件路径：{}", privateKey);
			}

			session = jsch.getSession(username, host, port);

			if (password != null) {
				session.setPassword(password);
			}
			Properties config = new Properties();
			config.put("StrictHostKeyChecking", "no");

			session.setConfig(config);
			session.connect();
			session.setTimeout(180000);
			Channel channel = session.openChannel("sftp");
			channel.connect();
			Amy.Log.info("sftp 连接的成功 ! \n 主机:{}端口:{} 用户名:{}", host, port, username);
			client = (ChannelSftp) channel;
		} catch (JSchException e) {
			Amy.Log.info("sftp 连接的失败! \n主机:{}端口:{} 用户名:{}", host, port, username);
			e.printStackTrace();
		}
	}

	/**
	 * 关闭连接 server
	 */
	public void do断开连接() {
		if (client != null) {
			if (client.isConnected()) {
				client.disconnect();
			}
		}
		if (session != null) {
			if (session.isConnected()) {
				session.disconnect();
			}
		}
	}

	void 进入(String ftp路径) {
		try {
			client.cd(ftp路径);
		} catch (SftpException e) {
			Amy.Log.info("此账号{}没有权限进入该路径{}", username, ftp路径);
		}
	}

	void 进入或创建目录(String ftp路径) {
		try {
			client.cd(ftp路径);
		} catch (SftpException e) {
			// 目录不存在，则创建文件夹
			String[] dirs = ftp路径.split("/");
			String tempPath = "";
			for (String dir : dirs) {
				if (null == dir || "".equals(dir))
					continue;
				tempPath += "/" + dir;
				try {
					client.cd(tempPath);
				} catch (SftpException ex) {
					try {
						client.mkdir(tempPath);
						client.cd(tempPath);
					} catch (SftpException e1) {
						Amy.Log.info("此账号{}没有权限创建路径", username);
						e1.printStackTrace();
					}

				}
			}
		}
	}

	/**
	 * 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory
	 * 
	 * @param 上传到ftp目录
	 * @param sftp保存文件名
	 * @param 输入文件流
	 */
	public void do上传(String 上传到ftp目录, String sftp保存文件名, InputStream 输入文件流)  {
		进入或创建目录(上传到ftp目录);
		try {
			client.put(输入文件流, sftp保存文件名);
		} catch (SftpException e) {
			Amy.Log.info("文件{} 无法上传到目录{}", sftp保存文件名, 上传到ftp目录);
			e.printStackTrace();
		} // 上传文件
	}

	/**
	 * 下载文件。
	 * 
	 * @param 下载目录
	 * @param 下载文件
	 * @param 本地保存路径
	 */
	public void do下载(String 下载目录, String 下载文件, String 本地保存路径) {
		if (下载目录 != null && !"".equals(下载目录)) {
			进入(下载目录);
		}
		File file = new File(本地保存路径);
		try {
			client.get(下载文件, new FileOutputStream(file));
		} catch (FileNotFoundException | SftpException e) {
			Amy.Log.info("文件{}/{} 无法下载", 下载目录, 下载文件);
			e.printStackTrace();
		}
	}

	/**
	 * 下载文件
	 * 
	 * @param 下载目录
	 * @param 下载文件
	 * @return 字节数组
	 */
	public InputStream do下载(String 下载目录, String 下载文件) {
		进入(下载目录);

		try {
			return client.get(下载文件);
		} catch (SftpException e) {
			Amy.Log.info("文件{}/{} 无法下载", 下载目录, 下载文件);
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * 删除文件
	 * 
	 * @param directory  要删除文件所在目录
	 * @param deleteFile 要删除的文件
	 */
	public void do删除Ftp端文件(String directory, String deleteFile) {
		try {
			client.cd(directory);
			client.rm(deleteFile);
		} catch (SftpException e) {		
			e.printStackTrace();
		}
	
	}

	/**
	 * 列出目录下的文件
	 * 
	 * @param directory 要列出的目录
	 * @param client
	 */
	public Vector<?> do列出目录下文件(String directory) throws SftpException {
		return client.ls(directory);
	}	
	public boolean is存在(String ftp文件路径) {
		try {
			SftpATTRS fatt=	client.lstat(ftp文件路径);
			if (fatt.isFifo()||fatt.isDir())
				return true;
			else
				return false;
		} catch (SftpException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	// 上传文件测试
	public static void demo() throws SftpException, IOException {
		SFtp sftp = new SFtp("root", "root", "ip", 22);
		sftp.do登录();
		System.out.println(sftp.client.isConnected());
		System.out.println(sftp.client.getExitStatus());
		for (int i = 0; i < 5; i++) {
			File file = new File("D:\\uploadFile\\ftp.txt");
			InputStream is = new FileInputStream(file);
			sftp.do上传("/root/nginx/uploadFile", System.currentTimeMillis() + ".txt", is);
		}
		sftp.do下载("/root/nginx/uploadFile/","001.txt", "D:\\downfile\\test.txt");
		sftp.do断开连接();
		System.out.println(sftp.client.isConnected());
	}



	
}
